package com.wugh.fast.module.web;

import cn.hutool.core.exceptions.ExceptionUtil;
import com.alibaba.fastjson.JSON;
import com.wugh.fast.kernel.util.HttpUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * 全局控制层的日志记录
 *
 * @author 吴冠辉
 * @date 2018/6/27 17:52
 */
@Slf4j
@Aspect
public class ControllerLoggerAspect {

    @Pointcut("@within(org.springframework.web.bind.annotation.RestController) ||@within(org.springframework.stereotype.Controller) ")
    public void controllerPointcut() {
    }

    @Around("controllerPointcut()")
    public Object doLog(ProceedingJoinPoint joinPoint) throws Throwable {
        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
        HttpServletRequest request = servletRequestAttributes.getRequest();
        String uri = request.getRequestURI();
        String method = request.getMethod();
        String ip = HttpUtils.getIpAddress(request);
        LocalDateTime start = LocalDateTime.now();
        try {
            Object rspObj = joinPoint.proceed();
            LocalDateTime end = LocalDateTime.now();
            if (log.isDebugEnabled()) {
                String methodParams = serializationParameter(joinPoint.getArgs());
                log.debug("{}:SUCC {} {} {} {} {}", ip, Duration.between(start, end).toMillis(), uri, method, methodParams, JSON.toJSON(rspObj));
            } else if (log.isInfoEnabled()) {
                log.info("{}:SUCC {} {} {}", ip, Duration.between(start, end).toMillis(), uri, method);
            }
            return rspObj;
        } catch (Exception e) {
            LocalDateTime end = LocalDateTime.now();
            if (log.isDebugEnabled()) {
                String methodParams = serializationParameter(joinPoint.getArgs());
                log.error("{}:FAIL {} {} {} {} {}", ip, Duration.between(start, end).toMillis(), uri, method, methodParams, ExceptionUtil.getRootCauseMessage(e));
                log.error("异常内存栈信息:", e);
            } else if (log.isInfoEnabled()) {
                log.error("{}:FAIL {} {} {} {}", ip, Duration.between(start, end).toMillis(), uri, method, ExceptionUtil.getRootCauseMessage(e));
            }
            throw e;
        }
    }

    /**
     * 序列化对象
     * <pre>
     *     由于序列化的时候,如果是request或response等对象,没办法使用json序列化,直接使用toString()方法即可
     * </pre>
     *
     * @param params
     * @return
     */
    private String serializationParameter(Object... params) {
        if (params == null) {
            return "[]";
        }
        List<String> paramStringList = new ArrayList<>(params.length);
        for (Object param : params) {
            String paramString;
            if (param instanceof ServletRequest) {
                paramString = param.toString();
            } else if (param instanceof ServletResponse) {
                paramString = param.toString();
            } else {
                try {
                    paramString = JSON.toJSONString(param);
                } catch (Exception e) {
                    paramString = param.toString();
                }
            }
            paramStringList.add(paramString);
        }
        return JSON.toJSONString(paramStringList);
    }
}
